package com.sri.ai.lpitools.gwtgui.callback;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.server.PropertyHandlerMapping;
import org.apache.xmlrpc.server.RequestProcessorFactoryFactory;
import org.apache.xmlrpc.server.XmlRpcHandlerMapping;
import org.apache.xmlrpc.server.XmlRpcServer;

/**
* The connection point for a service.  This class provides basic functionality to bind an
* end point to a given server while maintaining a stateful context for the service.
* 
 * A Quick SOA terminology primer.
* A server hosts end points.  End points are service offerings which implement contracts.
* Service Contracts are interfaces which define the methods that are offered by the service.
* 
* @author imiller
*
*/
public abstract class BasicCallBackServerRpcEndpoint {

       private Object serviceInstance;
       private XmlRpcServer server;
       
       /**
       * An internal class which replaces the logic used to generate handlers for the XmlRpcServer
       * when responding to a request.  With this handler a service instance can be specified which
       * will be common to every call.
       * 
        * @author imiller
       *
       */
       private class BaseRequestProcessorFactoryFactory implements RequestProcessorFactoryFactory {
              
              protected final RequestProcessorFactory factory = new BaseRequestProcessorFactory();
              protected final Object service;
              
              public BaseRequestProcessorFactoryFactory(Object service) {
                     this.service = service;
              }

              private class BaseRequestProcessorFactory implements RequestProcessorFactory {
                     public Object getRequestProcessor(XmlRpcRequest xmlRpcRequest) throws XmlRpcException {
                           return service;
                     }
              }

              @SuppressWarnings("rawtypes")
              @Override
              public RequestProcessorFactory getRequestProcessorFactory(Class arg0) throws XmlRpcException {
                     return this.factory;
              }
       }
       
       /**
       * A BasicRpcEndpoint supports holding a service reference which is passed into each new
       * RPC request processor.  This allows the service to be stateful between requests without
       * the use of an external state repository (like a database).
       * 
        * @param server
       *                         The XmlRpcServer this end point will be hosted on
       * @param serviceContract
       *                         The service contract for this end point.  This should be an interface
       *                         which the end point will bind to an implementation.
       * @param serviceInstance
       *                         An instance of the service contract which will be shared among requests.
       * @throws XmlRpcException
       */
       public BasicCallBackServerRpcEndpoint(XmlRpcServer server, Class<?> serviceContract, Object serviceInstance) throws XmlRpcException {
              XmlRpcHandlerMapping hm = server.getHandlerMapping();
              this.serviceInstance = serviceInstance;
              this.server = server;
              
              if (hm == null || !(hm instanceof PropertyHandlerMapping)) {
                     hm = new PropertyHandlerMapping();
                     server.setHandlerMapping(hm);
              } 
              PropertyHandlerMapping phm = (PropertyHandlerMapping)hm;
              phm.setRequestProcessorFactoryFactory(new BaseRequestProcessorFactoryFactory(serviceInstance));
              phm.addHandler("CallBackServer", serviceContract);
       }
       
       /**
       * Returns the internal instance used to spawn new service request processors.
       * @return
       *            The instance used to initialize the BasicRpcEndpoint and passed to each new request processor
       */
       protected Object getServiceInstance() {
              return this.serviceInstance;
       }
       
       /**
       * @return
       *            The RPC server this endpoint is associated with
       */
       protected XmlRpcServer getServer() {
              return this.server;
       }
}

